package com.cyy.daijia.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.UUID;
import com.cyy.daijia.common.constant.RedisConstant;
import com.cyy.daijia.common.execption.CException;
import com.cyy.daijia.common.result.ResultCodeEnum;
import com.cyy.daijia.model.entity.order.*;
import com.cyy.daijia.model.entity.order.*;
import com.cyy.daijia.model.enums.OrderStatus;
import com.cyy.daijia.model.form.order.OrderInfoForm;
import com.cyy.daijia.model.form.order.StartDriveForm;
import com.cyy.daijia.model.form.order.UpdateOrderBillForm;
import com.cyy.daijia.model.form.order.UpdateOrderCartForm;
import com.cyy.daijia.model.vo.base.PageVo;
import com.cyy.daijia.model.vo.order.*;
import com.cyy.daijia.model.vo.order.*;
import com.cyy.daijia.order.mapper.OrderBillMapper;
import com.cyy.daijia.order.mapper.OrderInfoMapper;
import com.cyy.daijia.order.mapper.OrderProfitsharingMapper;
import com.cyy.daijia.order.mapper.OrderStatusLogMapper;
import com.cyy.daijia.order.service.OrderInfoService;
import com.cyy.daijia.order.service.OrderMonitorService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@SuppressWarnings({"unchecked", "rawtypes"})
@RequiredArgsConstructor
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {
    private final OrderStatusLogMapper orderStatusLogMapper;
    private final RedisTemplate redisTemplate;
    private final OrderInfoMapper orderInfoMapper;
    private final RedissonClient redissonClient;
    private final OrderBillMapper orderBillMapper;
    private final OrderMonitorService orderMonitorService;
    @Autowired
    private OrderProfitsharingMapper orderProfitsharingMapper;
    @Override
    public void orderCancel(long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if(orderInfo.getStatus() == OrderStatus.WAITING_ACCEPT.getStatus()) {
            // 设置更新数据
            OrderInfo orderInfoUpt = new OrderInfo();
            orderInfoUpt.setId(orderId);
            orderInfoUpt.setStatus(OrderStatus.CANCEL_ORDER.getStatus());
            // 执行更新方法
            int rows = orderInfoMapper.updateById(orderInfoUpt);

            if(rows == 1) {
                //删除redis订单标识
                redisTemplate.delete(RedisConstant.ORDER_ACCEPT_MARK);
            }
        }
    }

    @Override
    public Boolean updateCouponAmount(Long orderId, BigDecimal couponAmount) {
        int row = orderBillMapper.updateCouponAmount(orderId, couponAmount);
        if(row != 1) {
            throw new CException(ResultCodeEnum.UPDATE_ERROR);
        }
        return true;
    }

    @Override
    public Long saveOrderInfo(OrderInfoForm orderInfoForm) {
        OrderInfo orderInfo = BeanUtil.copyProperties(orderInfoForm, OrderInfo.class);
        //订单号
        orderInfo.setOrderNo(UUID.randomUUID().toString().replaceAll("-",""));
        //设置订单状态
        orderInfo.setStatus(OrderStatus.WAITING_ACCEPT.getStatus());
        //保存信息
        save(orderInfo);

        //发送延迟消息
        sendOrderAcceptMessage(orderInfo.getId());
        //log
        this.log(orderInfo.getId(), orderInfo.getStatus());
        redisTemplate.opsForValue().set(RedisConstant.ORDER_ACCEPT_MARK,"0",RedisConstant.ORDER_ACCEPT_MARK_EXPIRES_TIME, TimeUnit.MINUTES);

        return orderInfo.getId();
    }

    private void sendOrderAcceptMessage(Long id) {
        try {
            //  创建一个队列
            RBlockingDeque<Object> blockingDeque = redissonClient
                    .getBlockingDeque("queue_cancel");
            //  将队列放入延迟队列中
            RDelayedQueue<Object> delayedQueue = redissonClient
                    .getDelayedQueue(blockingDeque);
            //  发送的内容
            delayedQueue.offer(id.toString(),
                    15, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public Integer getOrderStatus(Long orderId) {
        OrderInfo orderInfo = lambdaQuery().eq(OrderInfo::getId, orderId).one();
        if (orderInfo != null) {
            return orderInfo.getStatus();
        }
        return OrderStatus.NULL_ORDER.getStatus();
    }
    //司机抢单
    //实现分布式锁
    @Override
    public Boolean robNewOrder(Long driverId, Long orderId) {
        //查询所有订单中有存在的，利用redis
        if(!redisTemplate.hasKey(RedisConstant.ORDER_ACCEPT_MARK))
        {
            //"抢单失败“
            throw new CException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
        }
        //创建锁
        RLock lock = redissonClient.getLock(RedisConstant.ROB_NEW_ORDER_LOCK + orderId);
        try{
            //设置枚举类看字母能知道意义
            boolean tryLock = lock.tryLock(RedisConstant.ROB_NEW_ORDER_LOCK_WAIT_TIME, RedisConstant.ROB_NEW_ORDER_LOCK_LEASE_TIME, TimeUnit.SECONDS);
            if(tryLock){
                boolean b = lambdaUpdate()
                        .eq(OrderInfo::getId, orderId)
                        .eq(OrderInfo::getStatus, 1)
                        .set(OrderInfo::getStatus,2)
                        .set(OrderInfo::getAcceptTime,new Date())
                        .set(OrderInfo::getDriverId,driverId)
                        .update();
                //看如果update里面放东西就是修改后的数据
        /*LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getId,orderId).set;*/
                if(!b){
                    throw new CException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
                }
                //删除抢单标识
                redisTemplate.delete(RedisConstant.ORDER_ACCEPT_MARK);
            }
        }catch (Exception e){

        }finally {
            if(lock.isLocked()){
                lock.unlock();
            }
        }
        //司机抢单1查看状态，修改数据
        /*OrderInfo orderInfo = lambdaQuery()
                .eq(OrderInfo::getId, orderId)
                .one();
        //修改
        orderInfo.setDriverId(driverId);
        orderInfo.setAcceptTime(new Date());
        orderInfo.setStatus(2);
        boolean b = updateById(orderInfo);*/
       // orderInfo.setId(orderId);
        //乐观锁，以status之前值确定是之前的状态，以会修改之前的值为参数update order_info set status = 2, driver_id = #{driverId}, accept_time = now() where id = #{id} and status = 1kk

        return  true;
    }

    @Override
    public CurrentOrderInfoVo searchCustomerCurrentOrder(Long customerId) {
        List<OrderInfo> orderInfos = lambdaQuery()
                .eq(OrderInfo::getCustomerId, customerId)
                .in(OrderInfo::getStatus, OrderStatus.ACCEPTED,
                        OrderStatus.DRIVER_ARRIVED,
                        OrderStatus.UPDATE_CART_INFO,
                        OrderStatus.START_SERVICE,
                        OrderStatus.END_SERVICE,
                        OrderStatus.UNPAID)
                .orderByDesc(OrderInfo::getCreateTime)
                .list();
        CurrentOrderInfoVo currentOrderInfoVo = new CurrentOrderInfoVo();
        if(CollUtil.isNotEmpty(orderInfos)){
            OrderInfo orderInfo =orderInfos.get(0);
            currentOrderInfoVo.setIsHasCurrentOrder(true);
            currentOrderInfoVo.setStatus(orderInfo.getStatus());
            currentOrderInfoVo.setOrderId(orderInfo.getId());
        }
        else {
            currentOrderInfoVo.setIsHasCurrentOrder(false);
        }
        return currentOrderInfoVo;
    }

    @Override
    public CurrentOrderInfoVo searchDriverCurrentOrder(Long driverId) {
        List<OrderInfo> orderInfos = lambdaQuery()
                .eq(OrderInfo::getDriverId, driverId)
                .in(OrderInfo::getStatus, OrderStatus.ACCEPTED.getStatus(),
                        OrderStatus.DRIVER_ARRIVED.getStatus(),
                        OrderStatus.UPDATE_CART_INFO.getStatus(),
                        OrderStatus.START_SERVICE.getStatus(),
                        OrderStatus.END_SERVICE.getStatus())
                .orderByDesc(OrderInfo::getCreateTime)
                .list();
        CurrentOrderInfoVo currentOrderInfoVo = new CurrentOrderInfoVo();
        if(CollUtil.isNotEmpty(orderInfos)){
            OrderInfo orderInfo =orderInfos.get(0);
            currentOrderInfoVo.setIsHasCurrentOrder(true);
            currentOrderInfoVo.setStatus(orderInfo.getStatus());
            currentOrderInfoVo.setOrderId(orderInfo.getId());
        }
        else {
            currentOrderInfoVo.setIsHasCurrentOrder(false);
        }
        return currentOrderInfoVo;
    }

    @Override
    public Boolean driverArriveStartLocation(Long orderId, Long driverId) {
        //更新到达状态，到达时间
        boolean update = lambdaUpdate()
                .eq(OrderInfo::getId, orderId)
                .eq(OrderInfo::getDriverId, driverId)
                .set(OrderInfo::getStatus, 3)//表示司机已经到达
                .set(OrderInfo::getArriveTime, new Date())
                .update();
        if(update) return true;
        throw new CException(ResultCodeEnum.UPDATE_ERROR);
    }

    @Override
    public Boolean updateOrderCart(UpdateOrderCartForm updateOrderCartForm) {
        /*OrderInfo orderInfo = BeanUtil.copyProperties(updateOrderCartForm, OrderInfo.class);
        orderInfo.setStatus(OrderStatus.UPDATE_CART_INFO.getStatus());
        boolean update = lambdaUpdate()
                .eq(OrderInfo::getId, updateOrderCartForm.getOrderId())
                .eq(OrderInfo::getDriverId, updateOrderCartForm.getDriverId())
                .update(orderInfo);
        if(update) return true;
        throw new CException(ResultCodeEnum.UPDATE_ERROR);*/
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getId, updateOrderCartForm.getOrderId());
        queryWrapper.eq(OrderInfo::getDriverId, updateOrderCartForm.getDriverId());

        OrderInfo updateOrderInfo = new OrderInfo();
        BeanUtils.copyProperties(updateOrderCartForm, updateOrderInfo);
        updateOrderInfo.setStatus(OrderStatus.UPDATE_CART_INFO.getStatus());
        System.err.println("row"+1234341);
        //只能更新自己的订单
        int row = orderInfoMapper.update(updateOrderInfo, queryWrapper);
        System.err.println("row"+row);
        if(row == 1) {
            //记录日志
            this.log(updateOrderCartForm.getOrderId(), OrderStatus.UPDATE_CART_INFO.getStatus());
        } else {
            throw new CException(ResultCodeEnum.UPDATE_ERROR);
        }
        return true;
    }

    @Override
    public Boolean startDrive(StartDriveForm startDriveForm) {
        boolean update = lambdaUpdate()
                .eq(OrderInfo::getId, startDriveForm.getOrderId())
                .eq(OrderInfo::getDriverId, startDriveForm.getDriverId())
                .set(OrderInfo::getStatus, OrderStatus.START_SERVICE.getStatus())
                .set(OrderInfo::getStartServiceTime, new Date())
                .update();
        if(update) {
            //初始化订单监控统计数据
            OrderMonitor orderMonitor = new OrderMonitor();
            orderMonitor.setOrderId(startDriveForm.getOrderId());
            orderMonitorService.saveOrderMonitor(orderMonitor);
            return true;
        }
        throw new CException(ResultCodeEnum.UPDATE_ERROR);
    }

    @Override
    public Long getOrderNumByTime(String startTime, String endTime) {
        Long count = lambdaQuery()
                .lt(OrderInfo::getStartServiceTime, endTime)
                .ge(OrderInfo::getStartServiceTime, startTime)
                //.eq()
                .count();
        return count;
    }

    @Override
    public Boolean endDrive(UpdateOrderBillForm updateOrderBillForm) {
        boolean update = lambdaUpdate()
                .eq(OrderInfo::getId, updateOrderBillForm.getOrderId())
                .eq(OrderInfo::getDriverId, updateOrderBillForm.getDriverId())
                .set(OrderInfo::getStatus, OrderStatus.END_SERVICE.getStatus())
                .set(OrderInfo::getRealAmount, updateOrderBillForm.getTotalAmount())
                .set(OrderInfo::getFavourFee, updateOrderBillForm.getFavourFee())
                .set(OrderInfo::getEndServiceTime, new Date())
                .set(OrderInfo::getRealDistance, updateOrderBillForm.getRealDistance())
                .update();
        if(update){
            //添加具体账单数据
            OrderBill orderBill = BeanUtil.copyProperties(updateOrderBillForm, OrderBill.class);
            orderBill.setOrderId(updateOrderBillForm.getOrderId());
            orderBill.setPayAmount(orderBill.getTotalAmount());
            orderBillMapper.insert(orderBill);
            //添加分账信息数据
            OrderProfitsharing orderProfitsharing = BeanUtil.copyProperties(updateOrderBillForm, OrderProfitsharing.class);
            orderProfitsharing.setOrderId(updateOrderBillForm.getOrderId());
            orderProfitsharing.setRuleId(updateOrderBillForm.getProfitsharingRuleId());
            orderProfitsharing.setStatus(1);
            orderProfitsharingMapper.insert(orderProfitsharing);
            return true;

        }
        else throw new CException(ResultCodeEnum.UPDATE_ERROR);
    }

    @Override
    public PageVo findCustomerOrderPage(Page<OrderInfo> pageParam, Long customerId) {
       IPage<OrderInfo> page= orderInfoMapper.selectCustomerOrderPage(pageParam, customerId);
       PageVo pageVo=new PageVo();
       pageVo.setRecords(page.getRecords());
       pageVo.setPages(page.getPages());
       pageVo.setTotal(page.getTotal());
        return pageVo;
    }

    @Override
    public PageVo findDriverOrderPage(Page<OrderInfo> pageParam, Long driverId) {
        IPage<OrderInfo> page= orderInfoMapper.selectPageByDriverId(pageParam, driverId);

        return new PageVo(page.getRecords(), page.getPages(), page.getTotal());
    }

    @Override
    public OrderBillVo getOrderBillInfo(Long orderId) {
        OrderBill orderBill = Db.lambdaQuery(OrderBill.class)
                .eq(OrderBill::getOrderId, orderId)
                .one();
        return BeanUtil.copyProperties(orderBill ,  OrderBillVo.class);
    }

    @Override
    public OrderProfitsharingVo getOrderProfitsharing(Long orderId) {
        OrderProfitsharing orderProfitsharing = Db.lambdaQuery(OrderProfitsharing.class)
                .eq(OrderProfitsharing::getOrderId, orderId)
                .one();
        return BeanUtil.copyProperties(orderProfitsharing, OrderProfitsharingVo.class);
    }

    @Override
    public Boolean sendOrderBillInfo(Long orderId, Long driverId) {
        boolean update = lambdaUpdate()
                .eq(OrderInfo::getId, orderId)
                .eq(OrderInfo::getDriverId, driverId)
                .set(OrderInfo::getStatus, OrderStatus.UNPAID.getStatus())
                .update();
        if(update){
            return true;
        }
        throw  new CException(ResultCodeEnum.UPDATE_ERROR);
    }

    @Override
    public OrderPayVo getOrderPayVo(String orderNo, Long customerId) {
        if(customerId==null)
            customerId=1L;
        OrderPayVo orderPayVo= orderInfoMapper.getOrderPayVo(orderNo, customerId);
        if(orderPayVo!=null){
            String content= orderPayVo.getStartLocation()+"到"+orderPayVo.getEndLocation();
            orderPayVo.setContent(content);
        }
        System.err.println(orderPayVo.toString());
        return orderPayVo;
    }

    @Override
    public Boolean updateOrderPayStatus(String orderNo) {
        OrderInfo orderInfo = lambdaQuery().eq(OrderInfo::getOrderNo, orderNo).one();
        if(orderInfo.getStatus()!=OrderStatus.PAID.getStatus()&&orderInfo.getStatus()!=null){
            lambdaUpdate().eq(OrderInfo::getOrderNo, orderNo)
                    .set(OrderInfo::getStatus, OrderStatus.PAID.getStatus())
                    .set(OrderInfo::getPayTime, new Date()).update();
        }
        return true;
    }

    @Override
    public OrderRewardVo getOrderRewardFee(String orderNo) {
        OrderRewardVo orderRewardVo= orderInfoMapper.getOrderRewardFee(orderNo);
        return orderRewardVo;
    }

    public void log(Long orderId, Integer status) {
        OrderStatusLog orderStatusLog = new OrderStatusLog();
        orderStatusLog.setOrderId(orderId);
        orderStatusLog.setOrderStatus(status);
        orderStatusLog.setOperateTime(new Date());
        orderStatusLogMapper.insert(orderStatusLog);
    }

}
